package com.ruoyi.system.service.impl;

import java.io.*;
import java.util.*;

import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.utils.VideoUtil.VideoUtil;
import com.ruoyi.common.utils.bean.ProcessClearStream;
import com.ruoyi.common.utils.file.FileNameUtil;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.system.domain.Do.HzFileUrlDo;
import com.ruoyi.system.domain.HzFileUrl;
import com.ruoyi.system.domain.co.HzUploadInfoCo;
import com.ruoyi.system.mapper.HzCommentMapper;
import com.ruoyi.system.mapper.HzDanmakuMapper;
import com.ruoyi.system.mapper.HzFileUrlMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.HzUploadInfoMapper;
import com.ruoyi.system.domain.HzUploadInfo;
import com.ruoyi.system.service.IHzUploadInfoService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;

/**
 * 上传总信息Service业务层处理
 *
 * @author ruoyi
 * @date 2021-07-17
 */
@Service
public class HzUploadInfoServiceImpl implements IHzUploadInfoService {
    @Autowired
    private HzUploadInfoMapper hzUploadInfoMapper;   //上传文件信息

    @Autowired
    private HzFileUrlMapper fileUrlMapper;    //文件存放地址

    @Autowired
    private HzCommentMapper commentMapper;   //评论

    @Autowired
    private HzDanmakuMapper danmakuMapper;   //弹幕


    @Value("${ruoyi.profile}")
    private String profile;   //文件保存地址

    @Value("${ruoyi.http-url}")
    private String httpUrl;   //http隧道地址

    @Value("${server.servlet.context-path}")
    private String contextPath;    //应用访问路径


    /**
     * 文件地址获取
     *
     * @param id
     * @return
     * @throws Exception
     */
    @Override
    public List<Object> playVideoBYid(Long id) throws Exception {
        HzUploadInfo hzUploadInfo = hzUploadInfoMapper.selectHzUploadInfoById(id);
        List<HzFileUrl> filelist = fileUrlMapper.selectHzFileUrlByInfoId(id);
        List<Object> mapList = new ArrayList();
        Integer fileType = hzUploadInfo.getFileType();
        if (fileType == 1) {
            //套图  ->直接返回套图地址list
            for (HzFileUrl fileUrl : filelist) {
                mapList.add(fileUrl);
            }
        } else if (fileType == 2) {
            //1.判断此视频是否生成了m3u8文件  ,生成了下面直接返回m3u8文件地址
            HzFileUrlDo urlDo = new HzFileUrlDo();
            urlDo.setSrsUrl(httpUrl + contextPath + "videoFile/" + id + "/V.m3u8");
            mapList.add(urlDo);
        }
        return mapList;
    }

    /**
     * 上传总信息
     *
     * @param infoCo 上传总信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertHzUploadInfo(HzUploadInfoCo infoCo) throws Exception {
        File profiledir = new File(profile);
        if (!profiledir.exists()) profiledir.mkdir();

        List<Map<String, Object>> fileList = infoCo.getFileList();
        //保存上传文件信息
        Integer fileType = infoCo.getFileType();
        Map<String, Object> map = fileList.get(0);
        String surfaceploturl = (String) map.get("fileUrl");
        if (fileType == 1) {
            infoCo.setSurfacePlotUrl(surfaceploturl);  //默认第一张生成省略图
        } else if (fileType == 2) {
            // 生成视频省略图物理地址
            surfaceploturl = surfaceploturl.replace("/profile", profile);   //原视频物理地址
            String fileN = (String) map.get("fileName");
            String fileFormat = FileNameUtil.getFileSufix(fileN);   //文件后缀名
            //jpg
            VideoUtil.fetchFrame(surfaceploturl, ".jpg", null);
            String jpgUrl = surfaceploturl.replace(fileFormat, "jpg").replace(profile, "/profile");
            infoCo.setSurfacePlotUrl(jpgUrl);
            //gif
            VideoUtil.buildGif(surfaceploturl, null, null, null, null);
            String gifUrl = surfaceploturl.replace(fileFormat, "gif").replace(profile, "/profile");
            infoCo.setVideoGifUrl(gifUrl);
        }
        infoCo.setUpdateDate(new Date());
        infoCo.setFileCount(fileList.size());  //文件数量
        infoCo.setBrowseCount(0l);  //浏览次数默认0次
        int i = hzUploadInfoMapper.insertHzUploadInfo(infoCo);
        //插入单个文件物理存储信息
        for (Map<String, Object> fu : fileList) {
            HzFileUrl fileUrl = new HzFileUrl();
            fileUrl.setUploadInfoId(infoCo.getId());  //信息id
            String fileN = (String) fu.get("fileName");
            String fileName = FileNameUtil.getFilePrefix(fileN);
            String fileFormat = FileNameUtil.getFileSufix(fileN);
            fileUrl.setFileName(fileName);
            fileUrl.setFileFormat(fileFormat);
            String fileSize = (String) fu.get("fileSize");
            fileUrl.setFileSize(Long.parseLong(fileSize));
            String filePath = (String) fu.get("fileUrl");
            String pathStr = profile + filePath;
            pathStr = pathStr.replace("/profile", "");
            File file = new File(pathStr);   //源文件应该在分割完成之后删除
            if (fileType == 2) {
                File dir = new File(profile + "/videoFile");
                if (!dir.exists()) dir.mkdir();
                filePath = "/videoFile/" + infoCo.getId() + "/V.m3u8";
            }
            fileUrl.setFileUrl(filePath);
            fileUrlMapper.insertHzFileUrl(fileUrl);
            if (fileType == 2) {
                filePath = profile + "/videoFile/" + infoCo.getId();
                File m3u8File = new File(filePath);   //创建存放分割后的文件目录
                if (!m3u8File.exists()) m3u8File.mkdir();
                //视频文件切割处理
                String command = "ffmpeg -i " + pathStr + " -c copy -map 0 -f segment -segment_list " + filePath + "/V.m3u8 -segment_time 10 " + filePath + "/V-%05d.ts";
                String osName = System.getProperty("os.name");
                if (osName.equals("Windows 10")) {
                    String[] cmdarray = new String[]{"cmd", "/k", command};              //不弹框推流
                    RunCmd(cmdarray, file);
                } else {
                    String[] cmdarray = new String[]{"/bin/sh", "-c", command};
                    RunCmd(cmdarray, file);
                }
            }
        }
        return i;
    }

    /**
     * 异步线程推流
     *
     * @param cmdarray
     * @throws IOException
     * @descriptiona 在runtime执行大点的命令中，输入流和错误流会不断有流进入存储在JVM的缓冲区中，如果缓冲区的流不被读取被填满时，
     * 就会造成runtime的阻塞。所以在进行比如：大文件复制等的操作时，我们还需要不断的去读取JVM中的缓冲区的流，
     * 来防止Runtime的死锁阻塞。利用单独两个线程，分别处理process的getInputStream()和getErrorSteam()，
     * 防止缓冲区被撑满，导致阻塞；
     */
    public void RunCmd(String cmdarray[], File file) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                InputStream inputStream = null;
                InputStream errorStream = null;
                OutputStream outputStream = null;
                try {
                    Process process = Runtime.getRuntime().exec(cmdarray);
                    outputStream = process.getOutputStream();
                    outputStream.close();
                    //读取缓冲区返回得数据,不然会造成线程阻塞
                    inputStream = process.getInputStream();
                    errorStream = process.getErrorStream();
                    new ProcessClearStream(inputStream).start();
                    new ProcessClearStream(errorStream).start();
                    //阻塞方法, 导致当前线程等待.
                    int exitVal = process.waitFor();
                    System.out.println(exitVal == 0 ? "执行成功" : "执行失败");
                    boolean delete = FileUtils.deleteFile(file); //删除上传原始文件
                    System.out.println("文件删除: " + delete);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        System.out.println("关流......");
                        inputStream.close();
                        errorStream.close();
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t.start();
    }


    /**
     * 查询上传总信息
     *
     * @param id 上传总信息ID
     * @return 上传总信息
     */
    @Override
    public HzUploadInfo selectHzUploadInfoById(Long id) {
        return hzUploadInfoMapper.selectHzUploadInfoById(id);
    }

    /**
     * 查询上传总信息列表
     *
     * @param hzUploadInfo 上传总信息
     * @return 上传总信息
     */
    @Override
    public List<HzUploadInfo> selectHzUploadInfoList(HzUploadInfo hzUploadInfo) {
        return hzUploadInfoMapper.selectHzUploadInfoList(hzUploadInfo);
    }


    /**
     * 修改上传总信息
     *
     * @param hzUploadInfo 上传总信息
     * @return 结果
     */
    @Override
    public int updateHzUploadInfo(HzUploadInfo hzUploadInfo) {
        return hzUploadInfoMapper.updateHzUploadInfo(hzUploadInfo);
    }

    /**
     * 删除上传总信息对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteHzUploadInfoByIds(String ids) {
        String[] IDarray = Convert.toStrArray(ids);
        for (String id : IDarray) {
            deleteById(Long.valueOf(id));
            fileUrlMapper.deleteByUploadInfoId(Long.valueOf(id));
        }
        return hzUploadInfoMapper.deleteHzUploadInfoByIds(IDarray);
    }

    /**
     * 删除上传总信息信息
     *
     * @param id 上传总信息ID
     * @return 结果
     */
    @Override
    public int deleteHzUploadInfoById(Long id) {
        deleteById(id);
        fileUrlMapper.deleteByUploadInfoId(id);
        return hzUploadInfoMapper.deleteHzUploadInfoById(id);
    }

    public String checkTitleNameUnique(String titleName) {
        int count = hzUploadInfoMapper.checkTitleNameUnique(titleName);
        if (count > 0) {
            return "false";
        } else {
            return "true";
        }
    }


    /**
     * 根据id删除物理磁盘上的文件
     *
     * @param id
     * @return
     */
    @Override
    public void deleteById(Long id) {
        //删除弹幕和评论
        danmakuMapper.deleteByUploadInfoId(id);
        commentMapper.deleteByUploadInfoId(id);

        HzUploadInfo uploadInfo = selectHzUploadInfoById(id);
        List<HzFileUrl> fileUrls = fileUrlMapper.selectHzFileUrlByInfoId(id);
        //封面图
        String surfacePlotUrl = uploadInfo.getSurfacePlotUrl();
        surfacePlotUrl = surfacePlotUrl.replace("/profile", "");
        FileUtils.deleteFile(profile + surfacePlotUrl);
        Integer fileType = uploadInfo.getFileType();
        if (fileType == 1) {
            //图片
            for (HzFileUrl fileUrl : fileUrls) {
                String filePath = fileUrl.getFileUrl();
                filePath = filePath.replace("/profile", "");
                FileUtils.deleteFile(profile + filePath);
            }
        } else if (fileType == 2) { //视频
            String videoGifUrl = uploadInfo.getVideoGifUrl();
            videoGifUrl = videoGifUrl.replace("/profile", "");
            FileUtils.deleteFile(profile + videoGifUrl);
            //视频资源文件
            FileUtils.deleteFilej(profile + "/videoFile/" + id);
        }
    }

}
